/**
 * 
 */
package org.extdev.libraries.ltr;

import java.nio.DoubleBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;

import org.extdev.device.ltr.LTR212Channel;

import com.sun.jna.ptr.IntByReference;

/**
 * @author LAP
 *
 */
public class LTR212APILibraryFacade {
	
	private LTR212.ByReference ltr212;
	private String biosPath;
	private int dataPointsCount;
	private LTR212APILibrary dllInstance;
	private int maxChannelsCount;
	private ArrayList<LTR212Channel> channelsList;
	private LTRAPILibraryFacade ltrFacade;
	
	public LTR212APILibraryFacade() throws LTRException {
		super();
		dllInstance = LTR212APILibrary.INSTANCE;
		dataPointsCount = 100;
		biosPath = "C://LTR212.BIO";
		ltr212 = new LTR212.ByReference();
		inicilizeLTR212();
		ltr212.AcqMode = LTR212APIConstants.ACQ_MODE_HIGH_PRECISION;
		setMaxChannelsCount();
		channelsList = new ArrayList<LTR212Channel>(maxChannelsCount);
		ltrFacade = new LTRAPILibraryFacade(ltr212.Channel.getPointer());
	}
	
	private void setMaxChannelsCount() {
		switch (ltr212.AcqMode) {
		case LTR212APIConstants.ACQ_MODE_MEDIUM_PRECISION: case LTR212APIConstants.ACQ_MODE_HIGH_PRECISION:
			maxChannelsCount = 4; break;
		case LTR212APIConstants.ACQ_MODE_8CH_HIGH_PRECISION:
			maxChannelsCount = 8; break;
		}
	}
	
	public void inicilizeLTR212() throws LTRException {
		LTR212ExceptionGenerator.throwLTRException(dllInstance.LTR212_Init(ltr212));
	}
	
	public void openLTR212() throws LTRException {
		LTR212ExceptionGenerator.throwLTRException(
				dllInstance.LTR212_Open(
					ltr212, 
					ltrFacade.getAddres(), 
					ltrFacade.getPort(), 
					new String(ltrFacade.getCrateSN()), 
					ltrFacade.getChannel(), 
					biosPath));
	}

	/**
	 * @return the biosPath
	 */
	public String getBiosPath() {
		return biosPath;
	}

	/**
	 * @param biosPath the biosPath to set
	 */
	public void setBiosPath(String biosPath) {
		this.biosPath = biosPath;
	}
	
	public boolean isOpened() {
		boolean flag = false;
		if (dllInstance.LTR212_IsOpened(ltr212) == 0) flag = true;;
		return flag;
	}
	
	public void closeLTR212() throws LTRException {
		LTR212ExceptionGenerator.throwLTRException(dllInstance.LTR212_Close(ltr212));
	}
	
	public void setADC() throws LTRException {
		LTR212ExceptionGenerator.throwLTRException(dllInstance.LTR212_SetADC(ltr212));
	}
	
	public void start() throws LTRException {
		LTR212ExceptionGenerator.throwLTRException(dllInstance.LTR212_Start(ltr212));
	}
	
	public void stop() throws LTRException {
		LTR212ExceptionGenerator.throwLTRException(dllInstance.LTR212_Stop(ltr212));
	}
	
	public void testEEPROM() throws LTRException {
		LTR212ExceptionGenerator.throwLTRException(dllInstance.LTR212_TestEEPROM(ltr212));
	}
	
	public IntBuffer receive() throws LTRException {
		int size = dataPointsCount * 2 * channelsList.size();
		IntBuffer buffer = IntBuffer.allocate(size);
			LTR212ExceptionGenerator.throwLTRException(
				dllInstance.LTR212_Recv(
					ltr212, 
					buffer, 
					null, 
					size, 
					dllInstance.LTR212_CalcTimeOut(ltr212, size)));
		return buffer;
	}
	
	public DoubleBuffer processData(IntBuffer buffer) throws LTRException {
		int size = dataPointsCount * channelsList.size();
		DoubleBuffer dest = DoubleBuffer.allocate(size);
		IntByReference sz = new IntByReference(size * 2);
		LTR212ExceptionGenerator.throwLTRException(
			dllInstance.LTR212_ProcessData(
				ltr212, 
				buffer, 
				dest, 
				sz, 
				true));
		return dest;
	}

	/**
	 * @return the dataPointsCount
	 */
	public int getDataPointsCount() {
		return dataPointsCount;
	}

	/**
	 * @param dataPointsCount the dataPointsCount to set
	 */
	public void setDataPointsCount(int dataPointsCount) {
		if (dataPointsCount < 0) throw new IndexOutOfBoundsException("Points count must be above zero");
		this.dataPointsCount = dataPointsCount;
	}
	
	public int getACQMode() {
		return ltr212.AcqMode;
	}
	
	public void setACQMode(int mode) {
		ltr212.AcqMode = mode;
	}
	
	public void setChannels() {
		for(int i = 0; i < ltr212.LChTbl.length; i++) ltr212.LChTbl[i] = 0;
		for(LTR212Channel channel: channelsList) {
			ltr212.LChTbl[channelsList.indexOf(channel)] = dllInstance.LTR212_CreateLChannel(channel.getChannelNo(), channel.getScale());
		}
		ltr212.LChQnt = channelsList.size();
	}
	
	public void addChannel(LTR212Channel channel) {
		if (channel == null) throw new NullPointerException("channel in addChannel must be not null"); // null check
		channelsList.add(channel);
	}
	
	public void removeChannel(int index) {
		channelsList.remove(index);
	}
	
	public void removeAllChannels() {
		channelsList.clear();
	}
	
	public LTR212Channel getChannel(int index) {
		return channelsList.get(index);
	}
	
	public void useFabricCLB(boolean flag) {
		if (flag) ltr212.UseFabricClb = 1;
		else ltr212.UseFabricClb = 0;
	}
	
	public void useCLB(boolean flag) {
		if (flag) ltr212.UseClb = 1;
		else ltr212.UseClb = 0;
	}
	
	public boolean isUseFabricCLB() {
		return ltr212.UseFabricClb == 1;
	}
	
	public boolean isUseCLB() {
		return ltr212.UseClb == 1;
	}
	
	public int getChannelsCount() {
		return channelsList.size();
	}
	
	public int getLChannelsQuantity() {
		return ltr212.LChQnt;
	}
	
	public LTR212Channel getLTRChannel(int index) {
		return channelsList.get(index);
	}
	
	public void setRef(boolean flag) {
		if (flag) ltr212.REF = 1;
		else ltr212.REF = 0;
	}
	
	public boolean isRef() {
		return ltr212.REF == 1;
	}
	
	public void setAC(boolean flag) {
		if (flag) ltr212.AC = 1;
		else ltr212.AC = 0;
	}
	
	public boolean isAC() {
		return ltr212.AC == 1;
	}

	public void setChannel(short moduleNo) {
		ltrFacade.setChannel(moduleNo);
	}

	public void setCrateSN(byte[] bytes) {
		ltrFacade.setCrateSN(bytes);
	}
}
